import EventEmitter from 'eventemitter3'
import { getBrowserFileSystemStandardStorage } from '@/file_storage/browser_filesystem_storage'
import { singletonGetter } from '@/common/ts_utils'
import { fromJSONString, toJSONString } from '@/common/convert_utils'
import { StandardStorage } from '@/file_storage/standard_storage';
import path from '@/common/path';

export interface IWithLinkStorage {
  getLink: (fileName: string) => Promise<string>
}

export enum StorageTarget {
  Macro,
  TestSuite,
  CSV,
  Screenshot,
  Vision
}

export enum StorageManagerEvent {
  StrategyTypeChanged = 'StrategyTypeChanged',
  RootDirChanged = 'RootDirChanged',
  ForceReload = 'ForceReload'
}

export class StorageManager extends EventEmitter {

  constructor() {
    super()
  }

  // 获取目标
  getStorageForTarget(target: StorageTarget): StandardStorage {
    switch (target) {
      case StorageTarget.Macro: {
        const storage = getBrowserFileSystemStandardStorage({
          baseDir: 'macros',
          extensions: ['json'],
          shouldKeepExt: false,
          decode: (text: string, filePath: string) => {
            const obj = fromJSONString(text, path.basename(filePath), { withStatus: true })
            // console.log(obj, 'decode后的数据')
            // Note: use filePath as id
            return {
              ...obj,
              id: storage.filePath(filePath),
              path: storage.relativePath(filePath)
            } as any

          },
          encode: (data: any, fileName: string) => {
            const str = toJSONString({ ...data, commands: data.data.commands }, {
              withStatus: true,
              ignoreTargetOptions: false //!!this.getConfig?.()?.saveAlternativeLocators
            })
            // console.log(str, 'encode后的数据')
            // Note: BrowserFileSystemStorage only supports writing file with Blob
            // so have to convert it here in `encode`
            return new Blob([str])
          }
        })

          // FIXE: it's for test
          ; (window as any).newMacroStorage = storage

        return storage
      }
      case StorageTarget.CSV: {
        const storage = getBrowserFileSystemStandardStorage({
          baseDir: 'spreadsheets',
          extensions: ['csv'],
          shouldKeepExt: true,
          transformFileName: (path: string) => {
            return path.toLowerCase()
          }
        })
          ; (window as any).newCsvStorage = storage
        return storage
      }
      case StorageTarget.Screenshot: {
        const storage = getBrowserFileSystemStandardStorage({
          baseDir: 'screenshots',
          extensions: ['png'],
          shouldKeepExt: true,
          transformFileName: (path: string) => {
            return path.toLowerCase()
          }
        })
          ; (window as any).newScreenshotStorage = storage
        return storage
      }
      case StorageTarget.Vision: {
        const storage = getBrowserFileSystemStandardStorage({
          baseDir: 'visions',
          extensions: ['png'],
          shouldKeepExt: true,
          transformFileName: (path: string) => {
            return path.toLowerCase()
          }
        })
          ; (window as any).newVisionStorage = storage
        return storage
      }
      default:
        throw new Error(`Unsupported target: '${target}'`)
    }
  }

  getMacroStorage(): StandardStorage {
    return this.getStorageForTarget(StorageTarget.Macro)
  }

  getTestSuiteStorage(): StandardStorage {
    return this.getStorageForTarget(StorageTarget.TestSuite)
  }

  getCSVStorage(): StandardStorage & IWithLinkStorage {
    return <StandardStorage & IWithLinkStorage>this.getStorageForTarget(StorageTarget.CSV)
  }

  getVisionStorage() {
    return <StandardStorage & IWithLinkStorage>this.getStorageForTarget(StorageTarget.Vision)
  }

  getScreenshotStorage(): StandardStorage & IWithLinkStorage {
    return <StandardStorage & IWithLinkStorage>this.getStorageForTarget(StorageTarget.Screenshot)
  }
}

// Note: in panel window (`src/index.js`), `getStorageManager` is provided with `getMacros` in `extraOptions`
// While in `bg.js` or `csv_edtior.js`, `vision_editor.js`, `extraOptions` is omitted with no harm,
// because they don't read/write test suites
export const getStorageManager = singletonGetter(() => {
  return new StorageManager()
})
